﻿
Imports std
Imports storoomc
Imports rashare

Public Module handlers
    Public Function selectStoroom(ByRef host As String, ByRef port As Int32) As Boolean
        assert(config.storoomhosts.size() > 0 AndAlso config.storoomhosts.size() = config.storoomports.size() _
               , "did not get required storoomhosts and storoomports in configuration.")

        If config.ignorecrawlingtag Then
            copy(host, config.storoomhosts(0))
            copy(port, config.storoomports(0))
            Return True
        Else
            Static lastaccess As Int64 = 0
            Static lasthost As String = Nothing
            Static lastport As Int32 = 0
            If Now.Ticks - lastaccess <= 10 * 60 * 1000 * 1000 _
                AndAlso Not isemptystring(lasthost) AndAlso lastport <> 0 Then
                copy(host, lasthost)
                copy(port, lastport)
                Return True
            Else
                Dim i As Int64
                For i = 0 To config.storoomhosts.size() - 1
                    If Not storoom.modify(rashare.crawling, Nothing) Then
                        copy(host, config.storoomhosts(i))
                        copy(port, config.storoomports(i))
                        copy(lasthost, host)
                        copy(lastport, port)
                        lastaccess = Now.Ticks()
                        Exit For
                    End If
                Next

                Return i < config.storoomhosts.size()
            End If
        End If
    End Function

    Public Function getstoroom(ByRef host As String, ByRef port As Int32, ByRef retrytimes As Int64) As Boolean
        If selectStoroom(host, port) Then
            retrytimes = config.storoomretrytimes
            Return True
        Else
            Return False
        End If
    End Function

    Sub New()
        storoom.initial(AddressOf getstoroom)
    End Sub

    Private Function category(ByVal receiveData As map(Of String, String) _
                              , ByVal rtnData As map(Of String, String)) As Boolean
        Dim buff As bytes = Nothing
        If Not storoom.read(tagsname, buff) Then
            raiseError("cannot get category list from storoom, ignore request.", errorHandle.errorType.warning)
            Return False
        Else
            Dim cats As vector(Of String) = Nothing
            strsepar(encoding.utf8.GetString(buff.data), character.newline, cats, True)
            If cats.size() = 0 Then
                Return False
            End If

            Dim catset As [set](Of String) = Nothing
            catset = New [set](Of String)
            Dim i As Int64
            For i = 0 To cats.size() - 1
                kickNewlineChar(cats(i))
                catset.insert(cats(i))
            Next
            If catset.size() = 0 Then
                Return False
            End If

            If Not rankcategory(catset, cats) Then
                raiseError("cannot rank categories, ignore request.", errorHandle.errorType.warning)
                Return False
            End If

            rtnData.insert(rarankerProtocol.keys.category.count, Convert.ToString(cats.size()))
            For i = 0 To cats.size() - 1
                rtnData.insert(rarankerProtocol.keys.category.category + Convert.ToString(i), cats(i))
            Next

            Return True
        End If
    End Function

    Private Function feed(ByVal receiveData As map(Of String, String) _
                          , ByVal rtnData As map(Of String, String)) As Boolean
        Dim buff As bytes = Nothing
        If Not storoom.read(feedsname, buff) Then
            raiseError("cannot get feed list from storoom, ignore request.", errorHandle.errorType.warning)
            Return False
        Else
            Dim feeds As vector(Of String) = Nothing
            strsepar(encoding.utf8.GetString(buff.data), character.newline, feeds, True)
            If feeds.size() = 0 Then
                raiseError("do not get any feed from storoom, ignore request.", errorHandle.errorType.warning)
                Return False
            End If

            Dim feedset As [set](Of String) = Nothing
            feedset = New [set](Of String)
            Dim i As Int64
            For i = 0 To feeds.size() - 1
                kickLeftRightBlank(feeds(i))
                feedset.insert(feeds(i))
            Next
            If feedset.size() = 0 Then
                raiseError("do not get any feed from storoom, ignore request.", errorHandle.errorType.warning)
                Return False
            End If

            If Not rankfeed(feedset, feeds) Then
                raiseError("cannot rank feeds, ignore request.", errorHandle.errorType.warning)
                Return False
            End If

            rtnData.insert(rarankerProtocol.keys.feed.count, Convert.ToString(feeds.size()))
            For i = 0 To feeds.size() - 1
                rtnData.insert(rarankerProtocol.keys.feed.feed + Convert.ToString(i), feeds(i))
            Next

            Return True
        End If
    End Function

    Private Function rss_category(ByVal category As String, ByVal rtnData As map(Of String, String) _
                                  , ByRef index As Int64, ByVal resultCount As Int64) As Boolean
        Dim buff As bytes = Nothing
        If Not storoom.read(category, buff) Then
            raiseError("cannot get feed list for category " + category + ", ignore request." _
                       , errorHandle.errorType.warning)
            Return False
        Else
            Dim feeds As vector(Of String) = Nothing
            strsepar(encoding.utf8.GetString(buff.data), character.newline, feeds, True)
            If feeds.size() = 0 Then
                raiseError("do not get any feed for category " + category + ", ignore request." _
                            , errorHandle.errorType.warning)
                Return False
            End If

            Dim feedset As [set](Of String) = Nothing
            feedset = New [set](Of String)()
            Dim i As Int64
            For i = 0 To feeds.size() - 1
                kickLeftRightBlank(feeds(i))
                feedset.insert(feeds(i))
            Next
            If feedset.size() = 0 Then
                raiseError("do not get any feed for category " + category + ", ignore request." _
                            , errorHandle.errorType.warning)
                Return False
            End If

            Dim feedrank As vector(Of pair(Of String, Double)) = Nothing
            If Not rankcategoryfeed(feedset, category, feedrank) Then
                raiseError("cannot rank feeds for category " + category + ", ignore request." _
                           , errorHandle.errorType.warning)
                Return False
            End If

            For i = 0 To feedrank.size() - 1
                If Not rss_feed(feedrank(i).first, rtnData _
                                , ifoper(resultCount * feedrank(i).second < 1, 1, resultCount * feedrank(i).second) _
                                , index) Then
                    raiseError("cannot get rss result from feed " + feedrank(i).first + ", ignore this feed." _
                                , errorHandle.errorType.warning)
                End If
            Next

            Return True
        End If
    End Function

    Private Function rss_categories(ByVal receiveData As map(Of String, String) _
                                  , ByVal rtnData As map(Of String, String)) As Boolean
        Dim categorySet As [set](Of String) = Nothing
        If Not readlist(receiveData, rarankerProtocol.keys.rss_categories.categorycount _
                        , rarankerProtocol.keys.rss_categories.category, categorySet, True) Then
            raiseError("cannot read category list from receiveData, ignore request.", errorHandle.errorType.warning)
            Return False
        End If

        Dim eachResultCount As Int64
        If Not convertor.toint64(receiveData(rarankerProtocol.keys.rss_categories.resultcount), eachResultCount) _
            OrElse eachResultCount > config.maxresultcount Then
            raiseError("do not get valid " + rarankerProtocol.keys.rss_categories.resultcount _
                        + " parameter from receiveData, use default value " + configNaming.raranker.maxresultcount _
                        + " in config as " + Convert.ToString(config.maxresultcount), errorHandle.errorType.warning)
            eachResultCount = config.maxresultcount
        End If

        Dim categories As vector(Of String) = Nothing
        If Not rankcategory(categorySet, categories) Then
            raiseError("cannot rank categories, ignore request.", errorHandle.errorType.warning)
            Return False
        End If

        If categories Is Nothing OrElse categories.size() = 0 Then
            raiseError("do not get valid category list after ranking, ignore request.", errorHandle.errorType.warning)
            Return False
        End If

        eachResultCount \= categories.size()
        If eachResultCount <= 0 Then
            eachResultCount = 1
        End If

        Dim index As Int64
        index = 0
        For i = 0 To categories.size() - 1
            If Not rss_category(categories(i), rtnData, index, eachResultCount) Then
                raiseError("cannot get rss results for category " + categories(i) + ", ignore this category." _
                           , errorHandle.errorType.warning)
            End If
        Next

        If index > 0 Then
            rtnData.insert(rarankerProtocol.keys.rss_categories.itemcount, Convert.ToString(index))
            Return True
        Else
            Return False
        End If
    End Function

    Private Function rss_feed(ByVal feed As String, ByVal rtnData As map(Of String, String), ByVal resultCount As Int64 _
                              , ByRef index As Int64) As Boolean
        If resultCount = 0 Then
            Return False
        End If

        Dim buff As bytes = Nothing
        If storoom.read(feed, buff) Then
            Dim items As vector(Of String) = Nothing
            strsepar(encoding.utf8.GetString(buff.data), newlineChars, items, True)
            If items.size() = 0 Then
                raiseError("do not get any items of feed " + feed + ", ignore request.", errorHandle.errorType.warning)
                Return False
            End If
            Dim i As Int64
            For i = 0 To min(resultCount, items.size()) - 1
                rtnData(rarankerProtocol.keys.rss_feed.item + Convert.ToString(index)) = items(i)
                index += 1
            Next
            Return True
        Else
            raiseError("cannot get items of feed " + feed + ", ignore request.", errorHandle.errorType.warning)
            Return False
        End If
    End Function

    Private Function rss_feeds(ByVal receiveData As map(Of String, String) _
                               , ByVal rtnData As map(Of String, String)) As Boolean
        Dim feedset As [set](Of String) = Nothing
        If Not readlist(receiveData, rarankerProtocol.keys.rss_feeds.feedcount _
                        , rarankerProtocol.keys.rss_feeds.feed, feedset, True) Then
            raiseError("cannot read feed list from receiveData, ignore request.", errorHandle.errorType.warning)
            Return False
        End If

        Dim eachResultCount As Int64
        If Not convertor.toint64(receiveData(rarankerProtocol.keys.rss_feeds.resultcount), eachResultCount) _
            OrElse eachResultCount > config.maxresultcount Then
            raiseError("do not get valid " + rarankerProtocol.keys.rss_feeds.resultcount _
                        + " parameter from receiveData, use default value " + configNaming.raranker.maxresultcount _
                        + " in config as " + Convert.ToString(config.maxresultcount), errorHandle.errorType.warning)
            eachResultCount = config.maxresultcount
        End If

        Dim feeds As vector(Of String) = Nothing
        If Not rankfeed(feedset, feeds) Then
            raiseError("cannot rank feeds, ignore request.", errorHandle.errorType.warning)
            Return False
        End If

        If feeds Is Nothing OrElse feeds.size() = 0 Then
            raiseError("do not get valid feed list after ranking, ignore request.", errorHandle.errorType.warning)
            Return False
        End If

        eachResultCount \= feeds.size()
        If eachResultCount <= 0 Then
            eachResultCount = 1
        End If

        Dim index As Int64 = 0
        Dim i As Int64
        For i = 0 To feeds.size()
            If Not rss_feed(feeds(i), rtnData, eachResultCount, index) Then
                raiseError("cannot get rss result from feed " + feeds(i) + ", ignore this feed." _
                            , errorHandle.errorType.warning)
            End If
        Next

        If index > 0 Then
            rtnData.insert(rarankerProtocol.keys.rss_feeds.itemcount, Convert.ToString(index))
            Return True
        Else
            Return False
        End If
    End Function

    Private Function submit(ByVal receiveData As map(Of String, String) _
                            , ByVal rtnData As map(Of String, String)) As Boolean

    End Function

    Public Sub handle(ByVal handle As tcpServer2.talkHandle)
        Dim rtndata As nettransData = Nothing
        Dim receive As map(Of String, String) = Nothing
        Dim result As map(Of String, String) = Nothing
        result = New map(Of String, String)()
        Dim rtn As Boolean = False
        rtn = nettransDataParser.keyvaluepair(handle.receiveData, receive)
        If rtn Then
            Select Case receive(rarankerProtocol.keys.command)
                Case rarankerProtocol.values.command.category
                    rtn = category(receive, result)
                Case rarankerProtocol.values.command.feed
                    rtn = feed(receive, result)
                Case rarankerProtocol.values.command.rss_category
                    rtn = rss_categories(receive, result)
                Case rarankerProtocol.values.command.rss_feed
                    rtn = rss_feeds(receive, result)
                Case rarankerProtocol.values.command.submit
                    rtn = submit(receive, result)
                Case Else
                    raiseError("do not get valid command, ignore request.", errorHandle.errorType.warning)
                    rtn = False
            End Select
        Else
            raiseError("do not get valid receivedata, ignore request.", errorHandle.errorType.warning)
        End If

        If Not rtn Then
            result.insert(rarankerProtocol.keys.status, rarankerProtocol.values.status.failure)
        End If

        If Not nettransDataInserter.keyvaluepair(rtndata, result) Then
            raiseError("cannot insert keyvalue pairs to talkhandle return data, connection " _
                       + handle.remoteIPEndPoint().ToString() + "ignore request.", errorHandle.errorType.warning)
        ElseIf Not handle.return(rtndata) Then
            raiseError("cannot reply return data to handle, connection " + handle.remoteIPEndPoint().ToString() _
                       + ", ignore request.", errorHandle.errorType.warning)
        End If
    End Sub
End Module
